import { ComponentClass } from 'react'
import Taro, { Component, Config } from '@tarojs/taro'
import { View, Image, Text, Button } from '@tarojs/components'
import { connect } from '@tarojs/redux'

import FastProductApplyHeader from '../../components/fast-apply-header'
import ApplyForm from '../../components/apply-form'
import AgreeProtocolRadio from '../../components/agree-protocol-radio'
import ProductFormButtonGroup from '../../components/product-form-button-group'

import ApplyFormItem from '../../model/apply-form'

import './index.scss'
import headLineImg from '../../asset/images/fast-apply-header/head-line.png'

import { Utils } from '../../utils/utils';
import ProductUtils from '../../utils/product'
import { User as UserUtils } from '../../utils/user'
import ApplyService from '../../services/apply'
import { noConsole } from '../../config'
import Constants from '../../config/constants';

// const qqmapUtils = new QQmapUtils
const utils = new Utils()
const productUtils = new ProductUtils()
const userUtils = new UserUtils()
const applyService = new ApplyService()

// #region 书写注意
// 
// 目前 typescript 版本还无法在装饰器模式下将 Props 注入到 Taro.Component 中的 props 属性
// 需要显示声明 connect 的参数类型并通过 interface 的方式指定 Taro.Component 子类的 props
// 这样才能完成类型检查和 IDE 的自动提示
// 使用函数模式则无此限制
// ref: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/20796
//
// #endregion

type FormItem = {
  name: string,
  value: any,
}

type PageStateProps = {
  product: any,   // 产品对象
  allTimeLimitOptions: number[],  // 产品的贷款期限数组
  form: ApplyFormItem[],
  formValue: any,
  isAgreeProtocol: boolean,
  userCredit: any,    // 用户信用信息
  depositTimeEventSuffix: string,
}

type PageDispatchProps = {
  dispatchSave: (param: any) => void,
  dispatchGetFastProduct: (pid: string) => void,
  dispatchUpdateFormItem: (payload: {
    formItem: FormItem
  }) => void
  dispatchGetCredit: (callback?: Function) => void,
  dispatchUpdateCredit: (credit: any) => void,
  dispatchUpdateForm: (form: any) => void,
}

type PageOwnProps = {}

type PageState = {
  product_id: string,    // 产品id,
  deposit: number,       // 贷款额度
  time_limit: number,    // 贷款期限
}

type IProps = PageStateProps & PageDispatchProps & PageOwnProps

interface BankProductDetail {
  props: IProps;
  state: PageState;
}

@connect(({ fastProductApply, common, loading }) => ({
  ...fastProductApply,
  ...common,
  ...loading,
}), (dispatch) => ({
  dispatchSave(param: any) {
    dispatch({
      type: 'fastProductApply/save',
      payload: param
    })
  },
  dispatchGetFastProduct(pid: string) {
    dispatch({
      type: 'fastProductApply/getFastProductDetail',
      payload: {
        product_id: pid,
      }
    })
  },
  dispatchUpdateFormItem(payload: { formItem: FormItem }) {
    dispatch({
      type: 'fastProductApply/updateFormItem',
      payload,
    })
  },
  dispatchGetCredit(callback?: Function) {
    dispatch({
      type: 'common/getUserCredit',
      payload: {
        callback,
      },
    })
  },
  dispatchUpdateCredit(credit: any) {
    dispatch({
      type: 'common/updateUserCredit',
      payload: { credit },
    })
  },
  dispatchUpdateForm(form: any) {
    dispatch({
      type: 'fastProductApply/updateForm',
      payload: form
    })
  }
}))
class BankProductDetail extends Component {

  constructor(props) {
    super(props);
  }

  componentWillReceiveProps(nextProps) {

    // 显示加载中
    const productLoading = nextProps.effects['fastProductApply/getFastProductDetail']

    // 要发放在setTimeout里执行，否则小程序会报redux错误...  不知为啥
    if (productLoading) {
      setTimeout(() => {
        utils.showLoadingCenter()
      }, 0);
    } else {
      setTimeout(() => {
        utils.hideLoadingCenter()
      }, 0);
    }

    // 使用用户信用数据填写表单
    const curUserCredit = this.props.userCredit
    const nextUserCredit = nextProps.userCredit
    if (JSON.stringify(nextUserCredit) !== JSON.stringify(curUserCredit)) {

      setTimeout(() => {
        const creditCopy = Object.assign({}, nextUserCredit)
        delete creditCopy.city_code

        // 合并信用数据到当前form
        Object.assign(creditCopy, this.props.formValue)

        this.props.dispatchUpdateForm(creditCopy)
      }, 0);
    }
  }

  componentWillMount() {

    // 获取url中的 deposit 参数
    const { product_id, deposit, time_limit } = this.$router.params
    this.setState({
      product_id,
      deposit,
      time_limit,
    }, () => {
      // 更新表单
      this.props.dispatchUpdateFormItem({
        formItem: {
          name: 'loan_limit',
          value: this.state.deposit
        }
      })
      this.props.dispatchUpdateFormItem({
        formItem: {
          name: 'loan_date_limit',
          value: this.state.time_limit
        }
      })
    })

    // 检查是否已登录
    if (userUtils.isLoginValid()) {

      // 监听贷款期限改变
      this.initDepositTimeChangeWatch()

      // 监听申请事件
      this.initApplyWatch()
    } else {
      const url = `/pages/fastProductApply/index?product_id=${product_id}`
      userUtils.checkIsLogin(url)
    }
  }

  componentDidMount() {

    if (userUtils.isLoginValid()) {
      // 加载产品详情数据
      this.props.dispatchGetFastProduct(this.state.product_id)
  
      // 初始化表单
      this.initForm()
    }
  }

  componentWillUnmount() {
    // 取消监听贷款期限改变
    this.removeDepositTimeChangeWatch()
    // 取消监听申请事件
    this.removeApplyWatch()
  }

  componentDidShow() { }

  componentDidHide() { }

  render() {

    const { product, form, formValue, allTimeLimitOptions, depositTimeEventSuffix } = this.props

    return (
      <View className="bank-product-apply-step-two-container">
        {/* <!-- 头部信息分块 --> */}
        <View className="header">
          <View className="bank-product-apply-header">
            <FastProductApplyHeader product={product ? product : {}}
              form={formValue}
              allTimeLimitOptions={allTimeLimitOptions}
              eventRandomSuffix={depositTimeEventSuffix} />
          </View>
        </View>
        <View className="apply-info-box">
          <View className="head-line">
            <Image className="image" src={headLineImg}></Image>
            <Text className="head-text">申请资料</Text>
          </View>
          <ApplyForm form={form} formValue={formValue} dispatchType={'fastProductApply/updateFormItem'} />
        </View>
        {/* <!-- 提交申请分块 --> */}
        <View className="bottom-function-box">
          <View className="bottom-radio-box">
            <AgreeProtocolRadio isAgreeProtocol={this.props.isAgreeProtocol} dispatchType={'fastProductApply/save'} />
          </View>
          <ProductFormButtonGroup product={product}
            currentUrl={`/pages/fastProductApply/index?product_id=${this.state.product_id}`}
            eventRandomSuffix={this.props.depositTimeEventSuffix} />
        </View>
      </View>
    )
  }

  /**
   * 提交申请方法
   */
  submit = () => {

    if (userUtils.isLoginValid()) {

      if (!this.props.isAgreeProtocol) {
        Taro.showToast({
          title: '请同意《壹融时代服务条款》',
          icon: 'none',
        })
        return
      }

      const validatorResult = utils.formValidation(this.props.form, this.props.formValue)
      if (!validatorResult.isValidate) {
        Taro.showToast({
          title: validatorResult.msg,
          icon: 'none',
        })
        return
      }

      const { formValue, product } = this.props

      // 保存表单信息到local storage
      productUtils.saveApplyFormToStorage(formValue)

      // 提交订单
      utils.showLoadingCenter()
      applyService.addOrder(formValue, product)
        .then(res => {
          const { code, msg } = res
          utils.hideLoadingCenter()
          if (code === 0) {
            // 提交成功，跳转到结果页
            Taro.navigateTo({
              url: `/pages/stepApplyResult/index`
            })
          } else {
            setTimeout(() => {
              Taro.showToast({
                title: msg,
                icon: 'none',
              })
            }, 0)
          }

          // 更新用户信用信息
          this.props.dispatchUpdateCredit(formValue)
        }).catch(err => {
          utils.hideLoadingCenter()
        })
    } else {
      userUtils.checkIsLogin(`/pages/fastProductApply?product_id=${this.state.product_id}&deposit=${this.state.deposit}&time_limit=${this.state.time_limit}`)
    }
  }

  /**
   * 根据产品对象初始化表单数据
   */
  initForm() {
    const { formValue } = this.props
    const formCopy = Object.assign({}, formValue)

    const that = this
    // 从服务器请求信用数据
    this.props.dispatchGetCredit((userCredit) => {

      // 使用服务器数据初始化form
      Object.assign(formCopy, userCredit)
      // 不使用userCredit的city_code
      if (formCopy.city_code.length > 3) {
        formCopy.city_code = []
      }

      // 联系电话默认使用登录的电话号码
      const userInfo = userUtils.getUserFromLocalStorage()
      if (userInfo) {
        formCopy.tel = userInfo.mobile
      }

      // 加载缓存
      const formCache = productUtils.getApplyFormFromStorage()
      if (formCache) {
        Object.assign(formCopy, formCache)
      }

      that.props.dispatchSave({
        formValue: formCopy
      })
    })
  }

  /**
   * 初始化贷款期限改变监听
   */
  initDepositTimeChangeWatch() {
    Taro.eventCenter.on(`${Constants.FAST_PRODUCT_APPLY_TIME_CHANGE_EVENT}${this.props.depositTimeEventSuffix}`, (param) => {
      const { loan_date_limit } = param
      this.props.dispatchUpdateFormItem({
        formItem: {
          name: 'loan_date_limit',
          value: loan_date_limit,
        }
      })
    })
  }

  /**
   * 删除贷款期限改变监听
   */
  removeDepositTimeChangeWatch() {
    Taro.eventCenter.off(`${Constants.FAST_PRODUCT_APPLY_TIME_CHANGE_EVENT}${this.props.depositTimeEventSuffix}`)
  }

  /**
   * 监听申请产品事件
   */
  initApplyWatch() {
    const that = this
    Taro.eventCenter.on(`${Constants.FORM_GROUP_APPLY_EVENT}${this.props.depositTimeEventSuffix}`, () => {
      // 调用提交方法
      that.submit()
    })
  }

  /**
   * 删除申请事件监听
   */
  removeApplyWatch() {
    Taro.eventCenter.off(`${Constants.FORM_GROUP_APPLY_EVENT}${this.props.depositTimeEventSuffix}`)
  }
}

// #region 导出注意
//
// 经过上面的声明后需要将导出的 Taro.Component 子类修改为子类本身的 props 属性
// 这样在使用这个子类时 Ts 才不会提示缺少 JSX 类型参数错误
//
// #endregion

export default BankProductDetail as ComponentClass<PageOwnProps, PageState>
